'use strict';
var crypto = require('../utils/crypto');
var db = require('../utils/db');

var tokenMgr = require('./tokenmgr');
var roomMgr = require('./roommgr');
var userMgr = require('./usermgr');


var log4js = require('log4js');
var log = log4js.getLogger("socketService");



var io = null;
exports.start = function (config, mgr) {
	io = require('socket.io')(config.SOCKET_PORT);
	io.set("heartbeat timeout", 5000);
	io.set('heartbeat interval', 5000);
	io.sockets.on('connection', function (socket) {
		socket.on('login', function (data) {
			data = JSON.parse(data);
			if (socket.userId != null) {
				//已经登陆过的就忽略
				return;
			}
			var token = data.token;
			var roomId = data.roomid;
			var time = data.time;
			var sign = data.sign;
			log.debug("roomId == " + roomId + " token == " + token + " time == " + time + " sign == " + sign);

			//检查参数合法性
			if (token == null || roomId == null || sign == null || time == null) {
				log.warn("errcode == 1 invalid parameters");
				socket.emit('login_result', { errcode: 1, errmsg: "invalid parameters" });
				return;
			}

			//检查参数是否被篡改
			var md5 = crypto.md5(roomId + token + time + config.ROOM_PRI_KEY);
			if (md5 != sign) {
				log.debug("errcode == 2 login failed. invalid sign!");
				socket.emit('login_result', { errcode: 2, errmsg: "login failed. invalid sign!" });
				return;
			}

			//检查token是否有效
			if (tokenMgr.isTokenValid(token) == false) {
				log.debug("errcode == 3 token out of time.");
				socket.emit('login_result', { errcode: 3, errmsg: "token out of time." });
				return;
			}

			//检查房间合法性
			var userId = tokenMgr.getUserID(token);
			var roomId = roomMgr.getUserRoom(userId);

			userMgr.bind(userId, socket);
			socket.userId = userId;

			//返回房间信息
			var roomInfo = roomMgr.getRoom(roomId);
			if (roomInfo == null) {
				log.debug("errcode == 4 room doesn't exist!");
				socket.emit('login_result', { errcode: 4, errmsg: "room doesn't exist!" });
				return;
			}
			var seatIndex = roomMgr.getUserSeat(userId);
			roomInfo.seats[seatIndex].ip = socket.handshake.address;

			var userData = null;
			var seats = [];
			var len = roomInfo.seats.length;
			var isCanBegin = true;
			for (var i = 0; i < len; ++i) {
				var rs = roomInfo.seats[i];
				var online = false;
				if (rs.userId > 0) {
					online = userMgr.isOnline(rs.userId);
				}
				seats.push({
					userid: rs.userId,
					ip: rs.ip,
					score: rs.score,
					name: rs.name,
					online: online,
					ready: rs.ready,
					seatindex: i
				});
				isCanBegin = rs.ready;

				if (userId == rs.userId) {
					userData = seats[i];
				}
			}

			db.getGameInfo(function (retVal) {
				if (retVal != null) {
					//通知前端
					var ret = {
						errcode: 0,
						errmsg: "ok",
						data: {
							roomid: roomInfo.id,
							conf: roomInfo.conf,
							numofgames: roomInfo.numOfGames,
							seats: seats,
							loglevel: retVal.log_level  //-1--不打印 0--全打印 1--部分
						}
					};
					socket.emit('login_result', ret);

					//通知其它客户端
					userMgr.broadcastInRoom('new_user_comes_push', userData, userId);

					//游戏管理
					socket.gameMgr = roomInfo.gameMgr;

					//登录完成
					socket.emit('login_finished');

					//玩家上线，强制设置为TRUE
					if (isCanBegin) {
						socket.gameMgr.setReady(userId);
					}
				}
			});
		});

		//断线重连
		socket.on('reconnect_ok', function (data) {
			data = JSON.parse(data);
			if (socket.userId != null) {
				return;
			}
			var token = data.token;
			var roomId = data.roomid;
			var time = data.time;
			var sign = data.sign;
			log.debug("reconnect roomId == " + roomId + " token == " + token + " time == " + time + " sign == " + sign);

			//检查参数合法性
			if (token == null || roomId == null || sign == null || time == null) {
				log.warn("errcode == 1 invalid parameters");
				socket.emit('login_result', { errcode: 1, errmsg: "invalid parameters" });
				return;
			}

			//检查参数是否被篡改
			var md5 = crypto.md5(roomId + token + time + config.ROOM_PRI_KEY);
			if (md5 != sign) {
				log.debug("errcode == 2 login failed. invalid sign!");
				socket.emit('login_result', { errcode: 2, errmsg: "login failed. invalid sign!" });
				return;
			}

			//检查token是否有效
			if (tokenMgr.isTokenValid(token) == false) {
				log.warn("errcode == 3 token out of time.");
				socket.emit('login_result', { errcode: 3, errmsg: "token out of time." });
				return;
			}

			//检查房间合法性
			var userId = tokenMgr.getUserID(token);
			var roomId = roomMgr.getUserRoom(userId);

			userMgr.bind(userId, socket);
			socket.userId = userId;

			//返回房间信息
			var roomInfo = roomMgr.getRoom(roomId);
			if (roomInfo != null) {
				var seatIndex = roomMgr.getUserSeat(userId);
				if (roomInfo.seats != undefined) {
					roomInfo.seats[seatIndex].ip = socket.handshake.address;
				}
				socket.gameMgr = roomInfo.gameMgr;
			} else {
				log.warn("errcode == 4 room doesn't exist!");
				socket.emit('login_result', { errcode: 4, errmsg: "room doesn't exist!" });
				return;
			}

			//发送同步信息
			if (socket.gameMgr != null) {
				socket.gameMgr.reconnectOK(socket.userId);
			}
		});

		socket.on('ready', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			if (socket.gameMgr != null) {
				socket.gameMgr.setReady(userId);
			}
			userMgr.broadcastInRoom('user_ready_push', { userid: userId, ready: true }, userId, true);
		});

		//矩离
		socket.on('user_distance', function (data) {
			if (socket.userId == null) {
				return;
			}
			var otherUserIds = data;
			socket.gameMgr.userDistance(socket.userId, otherUserIds);
		});

		//定缺
		socket.on('dingque', function (data) {
			if (socket.userId == null) {
				return;
			}
			var que = data;
			socket.gameMgr.dingQue(socket.userId, que);
		});

		//出牌
		socket.on('chupai', function (data) {
			if (socket.userId == null) {
				return;
			}
			var pai = data;
			socket.gameMgr.chuPai(socket.userId, pai);
		});

		//报听
		socket.on('baoting', function (data) {
			if (socket.userId == null) {
				return;
			}
			var isBaoTing = data;
			socket.gameMgr.baoTing(socket.userId, isBaoTing);
		});

		//碰
		socket.on('peng', function (data) {
			if (socket.userId == null) {
				return;
			}
			socket.gameMgr.peng(socket.userId);
		});

		//杠
		socket.on('gang', function (data) {
			if (socket.userId == null || data == null) {
				return;
			}
			var pai = -1;
			if (typeof (data) == "number") {
				pai = data;
			}
			else if (typeof (data) == "string") {
				pai = parseInt(data);
			}
			else {
				log.warn("gang:invalid param");
				return;
			}
			socket.gameMgr.gang(socket.userId, pai);
		});

		//胡
		socket.on('hu', function (data) {
			if (socket.userId == null) {
				return;
			}
			socket.gameMgr.hu(socket.userId);
		});

		//过  遇上胡，碰，杠的时候，可以选择过
		socket.on('guo', function (data) {
			if (socket.userId == null) {
				return;
			}
			socket.gameMgr.guo(socket.userId);
		});

		//聊天
		socket.on('chat', function (data) {
			if (socket.userId == null) {
				return;
			}
			var chatContent = data;
			userMgr.broadcastInRoom('chat_push', { sender: socket.userId, content: chatContent }, socket.userId, true);
		});

		//快速聊天
		socket.on('quick_chat', function (data) {
			if (socket.userId == null) {
				return;
			}
			var chatId = data;
			userMgr.broadcastInRoom('quick_chat_push', { sender: socket.userId, content: chatId }, socket.userId, true);
		});

		//语音聊天
		socket.on('voice_msg', function (data) {
			if (socket.userId == null) {
				return;
			}
			log.debug(data.length);
			userMgr.broadcastInRoom('voice_msg_push', { sender: socket.userId, content: data }, socket.userId, true);
		});

		//表情
		socket.on('emoji', function (data) {
			if (socket.userId == null) {
				return;
			}
			var phizId = data;
			userMgr.broadcastInRoom('emoji_push', { sender: socket.userId, content: phizId }, socket.userId, true);
		});

		//退出房间
		socket.on('exit', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				log.warn("exit fail for user id is null");
				return;
			}

			var roomId = roomMgr.getUserRoom(userId);
			if (roomId == null) {
				log.warn("exit fail for room id is null");
				return;
			}

			//如果游戏已经开始，则不可以
			if (socket.gameMgr.hasBegan(roomId)) {
				log.warn("exit fail for game has begin");
				return;
			}

			//如果是房主，则只能走解散房间
			if (roomMgr.isCreator(userId)) {
				log.warn("exit fail for creator only release room");
				return;
			}

			//通知其它玩家，有人退出了房间
			userMgr.broadcastInRoom('exit_notify_push', userId, userId, false);
			socket.emit('exit_result');

			//退出清除玩家数据
			roomMgr.exitRoom(userId);
			userMgr.del(userId);

			//释放链接
			setTimeout(function () {
				socket.disconnect();
				userMgr.del(userId);
				socket.userId = null;
			}, 2000);
		});

		//买底或顶底
		socket.on('buy_and_double_base', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}

			var type = data;
			socket.gameMgr.setBuyOrDoubleBase(userId, type);
		});

		//解散房间
		socket.on('dispress', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}

			var roomId = roomMgr.getUserRoom(userId);
			if (roomId == null) {
				return;
			}

			//如果游戏已经开始，则不可以
			if (socket.gameMgr.hasBegan(roomId)) {
				return;
			}

			//如果不是房主，则不能解散房间
			if (roomMgr.isCreator(roomId, userId) == false) {
				return;
			}

			userMgr.broadcastInRoom('dispress_push', {}, userId, true);
			setTimeout(function () {
				userMgr.kickAllInRoom(roomId);
				roomMgr.destroy(roomId);
				socket.disconnect();
				userMgr.del(userId);
				socket.userId = null;
			}, 1000);
		});

		//解散房间
		socket.on('dissolve_request', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				log.warn('userId is null');
				return;
			}

			var roomId = roomMgr.getUserRoom(userId);
			if (roomId == null) {
				log.warn('roomId is null');
				return;
			}

			//如果游戏未开始，则不可以
			if (socket.gameMgr.hasBegan(roomId) == false) {
				log.warn('game is no run');
				return;
			}

			//允许重复申请解散,但结束时间不变
			var ret = socket.gameMgr.dissolveRequest(roomId, userId);
			if (ret != null && ret.dr != null) {
				var dr = ret.dr;
				if (dr.endTime != null) {
					var ramaingTime = (dr.endTime - Date.now()) / 1000;
					var data = {
						time: ramaingTime,
						states: dr.states
					}
					console.log("user apply to release room ", userId, roomId);
					userMgr.broadcastInRoom('dissolve_notice_push', data, userId, true);
				}
			}
		});

		socket.on('dissolve_agree', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}

			var roomId = roomMgr.getUserRoom(userId);
			if (roomId == null) {
				return;
			}

			var ret = socket.gameMgr.dissolveAgree(roomId, userId, true);
			if (ret != null && ret.dr != null) {
				var dr = ret.dr;
				if (dr.endTime != null) {
					var ramaingTime = (dr.endTime - Date.now()) / 1000;
					var data = {
						time: ramaingTime,
						states: dr.states
					}
					console.log("user agree to release room ", userId, roomId);
					userMgr.broadcastInRoom('dissolve_notice_push', data, userId, true);
				}
				console.log("dissolve_agree dr states ", dr.states, dr.states.length);
				let agreeNum = 0;
				let unAgreeNum = 0;
				for (let i = 0; i < dr.states.length; ++i) {
					if (dr.states[i] == null || dr.states[i] == false) {
						++unAgreeNum;
					} else {
						++agreeNum;
					}
				}
				console.log("dissolve_agree state ", dr.states, agreeNum, unAgreeNum);
				if (unAgreeNum == 0) {
					//通知其它玩家，有人退出了房间
					userMgr.broadcastInRoom('exit_notify_push', userId, userId, true);
					userMgr.broadcastInRoom('exit_result', userId, userId, true);
					socket.gameMgr.doDissolve(roomId);
				}
			}
		});

		socket.on('dissolve_reject', function (data) {
			var userId = socket.userId;

			if (userId == null) {
				return;
			}

			var roomId = roomMgr.getUserRoom(userId);
			if (roomId == null) {
				return;
			}

			var ret = socket.gameMgr.dissolveAgree(roomId, userId, false);
			if (ret != null) {
				console.log("user reject to release room ", userId, roomId);
				userMgr.broadcastInRoom('dissolve_cancel_push', {}, userId, true);
			}
		});

		socket.on('testNet', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			userMgr.sendMsg(socket.userId, 'testNet_push');
		});

		socket.on('hope_mo_pai', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			var pai = data;
			socket.gameMgr.hopeMoPai(userId, pai);
		});

		socket.on('get_pei_pai_config', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			if (socket != null && socket.gameMgr != null) {
				socket.gameMgr.getPeipaiConfig(userId);
			}
		});

		//获取牌型对应的牌集合
		socket.on('get_card_pai_of_type', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			var type = data;
			if (socket != null && socket.gameMgr != null) {
				socket.gameMgr.getCardPaiOfType(userId, type);
			}
		});

		//出一组牌或一张牌后牌型变化
		socket.on('chu_card', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			var cardData = data;
			if (socket != null && socket.gameMgr != null) {
				socket.gameMgr.chuCard(userId, cardData);
			}
		});

		//取消出牌
		socket.on('cannel_chu_card', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			var channelNO = data;
			if (socket != null && socket.gameMgr != null) {
				socket.gameMgr.cancelChuCard(userId, channelNO);
			}
		});

		//确认出牌
		socket.on('play_out', function (data) {
			var userId = socket.userId;
			if (userId == null) {
				return;
			}
			var isOut = data;
			if (socket != null && socket.gameMgr != null) {
				socket.gameMgr.playOut(userId, isOut);
			}
		});
	});

	log.info("game server is listening on " + config.SOCKET_PORT);
};